package servidor;

import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import static java.lang.Math.abs;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.rmi.*;
import java.rmi.server.*;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

////////////////////////////////////////////////////////////////////////////////
public class ServidorImpl extends UnicastRemoteObject implements ServidorInterface, Runnable {

    private Vector vClientAlert; //VECTOR DE ALERTAS (AlertaServidor) AÑADIDAS POR LOS CLIENTES
    private Vector vCotizaciones; //VECTOR CON LOS VALORES DE LA BOLSA
    private volatile boolean done = false;

////////////////////////////////////////////////////////////////////////////////      
    public ServidorImpl() throws RemoteException {
        super();
        vClientAlert = new Vector();
        vCotizaciones = new Vector();

        Thread thread = new Thread(this);
        thread.start();
    }

////////////////////////////////////////////////////////////////////////////////
    @Override
    public String sayConnected() throws java.rmi.RemoteException {
        return ("Has conectado con el servidor");
    }

////////////////////////////////////////////////////////////////////////////////
    @Override
    public synchronized void registerForCallback(AlertaServidor alertaServidor) throws java.rmi.RemoteException {
        if (!(vClientAlert.contains(alertaServidor))) {

            vClientAlert.addElement(alertaServidor);
            System.out.println("\nNUEVA ALERTA REGISTRADA: Empresa=" + alertaServidor.getAlerta().getEmpresa() + " Precio=" + alertaServidor.getAlerta().getPrecio());
        }
    }
    
////////////////////////////////////////////////////////////////////////////////
    //Esta funcion borra del vector de alertasServidor del servidor, todos las alertas relacionadas con el cliente de la alerta pasada como parametro.
    @Override
    public synchronized void unregisterForCallback(AlertaServidor alertaS) throws java.rmi.RemoteException {
        for (int i = 0; i < vClientAlert.size(); i++) {

            System.out.println("\n pos " + i + "  Elementos en el vector de alertas del servidor: " + vClientAlert.size());

            AlertaServidor asTemp = (AlertaServidor) vClientAlert.elementAt(i);

            if (asTemp.getClientObject().equals(alertaS.getClientObject())) {
                vClientAlert.remove(i);
                System.out.println("\n" + i + " SE HA BORRADO DEL SERVIDOR LA ALERTA");
                i--;
            } else {

                System.out.println("\n" + i + " NO SE HA BORRADO DEL SERVIDOR LA ALERTA");

            }
        }
    }

////////////////////////////////////////////////////////////////////////////////
    //EL CALLBACK PARA CADA CLIENTE Y CADA ALERTA SE HACE EN LA FUNCION DE COMPROBACION DE ALERTAS
    private synchronized void callBackAlerta(AlertaServidor aS, String accion) throws java.rmi.RemoteException {
        System.out.println("\nAlerta " + accion + " callback: " + aS.getClientObject().notificarAlerta(aS.getAlerta(), accion));
    }

////////////////////////////////////////////////////////////////////////////////            
    private synchronized void parsearWeb() { //public Vector parsearWeb
        try {
            URL url = new URL("http://www.bolsamadrid.es/esp/aspx/Mercados/Precios.aspx?indice=ESI100000000&punto=indice");
            System.out.println("\n\n\nLEEMOS DATOS DE: " + url);

            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy2.usc.es", 8080));
            BufferedReader in = new BufferedReader(new InputStreamReader(((HttpURLConnection) url.openConnection(proxy)).getInputStream()));

            String htmlDoc = "";
            String inputLine;

            while ((inputLine = in.readLine()) != null) {
                htmlDoc = htmlDoc + "\n" + inputLine;    //LEEMOS EL CODIGO HTML DE LA WEB
            }

            Document doc = (Document) Jsoup.parse(htmlDoc);//PARSEAMOS LA WEB CON JSOUP

            Elements seleccion = doc.select("tr[align=right]");
            Iterator<Element> ite = seleccion.iterator();

            vCotizaciones.removeAllElements(); //VACIAMOS EL VECTOR DE COTIZACIONES. LO VAMOS A RELLENAR CON LAS COTIZACIONES ACTUALIZADAS.

            ite.next();//ASÍ NOS EVITAMOS LA PRIMERA TABLA DEL HTML, TABLA RESUMEN DEL IBEX35
            while (ite.hasNext()) {
                Element elAux = ite.next();
                Cotizacion cotizacion = new Cotizacion(elAux.child(0).text(), Float.parseFloat(elAux.child(1).text().replace(',', '.')));
                cotizacion.imprimirCotizacion();
                vCotizaciones.addElement(cotizacion);
            }
        } catch (IOException ex) {
            Logger.getLogger(ServidorImpl.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

////////////////////////////////////////////////////////////////////////////////
    //ESTE METODO COMPARA LOS ELEMENTOS DEL VECTOR COTIZACIONES CON LOS ELEMENTOS DEL VECTOR DE ALERTAS REGISTRADAS
    // Y REALIZA UN CALLBACK AL CLIENTE SI LA COMPROBACION ES SATISFACTORIA
    private synchronized void comprobarAlertas() throws java.rmi.RemoteException {

        for (int i = 0; i < vCotizaciones.size(); i++) {
            Cotizacion cotAux = (Cotizacion) vCotizaciones.elementAt(i);
            float cotizacionValor = cotAux.getValor();

            for (int j = 0; j < vClientAlert.size(); j++) {
                AlertaServidor asAux = (AlertaServidor) vClientAlert.elementAt(j);
                float alertaPrecio = asAux.getAlerta().getPrecio();

                if (cotAux.getEmpresa().equals(asAux.getAlerta().getEmpresa())) { //COMPARAMOS LOS NOMBRES

                    if ((alertaPrecio < 0) && (cotizacionValor <= abs(alertaPrecio))) { //SI LA ALERTA DEFINIDA POR EL CLIENTE TIENE VALOR NEGATIVO, SIGNIFICA QUE LA ALERTA ES DE COMPRA, PORQUE VA A RESTAR DINERO
                        callBackAlerta(asAux, "COMPRA");  //AVISO DE COMPRA
                        vClientAlert.remove(j);
                    }

                    if ((alertaPrecio > 0) && (cotizacionValor >= alertaPrecio)) { //SI LA ALERTA DEFINIDA POR EL CLIENTE TIENE VALOR POSITIVO, SIGNIFICA QUE LA ALERTA ES DE VENTA, PORQUE VA A SUMAR DINERO 
                        callBackAlerta(asAux, "VENTA");  //AVISO DE VENTA
                        vClientAlert.remove(j);
                    }
                }
            }
        }
    }

////////////////////////////////////////////////////////////////////////////////
    @Override
    public void run() {
        while (!done) {
            try {
                Toolkit.getDefaultToolkit().beep(); //REPRODUCE UN AVISO SONORO
                this.parsearWeb();
                this.comprobarAlertas();

                //Dormimos el hilo                  
                Thread.sleep(60000);

            } catch (InterruptedException ex) {
                Logger.getLogger(Thread.class.getName()).log(Level.SEVERE, null, ex);
            } catch (RemoteException ex) {
                Logger.getLogger(ServidorImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

////////////////////////////////////////////////////////////////////////////////
//ESTA FUNCION ES LA QUE CAMBIA LA VARIABLE DE PARADA DEL THREAD    
    public void setDone() {
        done = true;
    }
////////////////////////////////////////////////////////////////////////////////
}
